package com.gitee.wsl.compose.ui.richtext.edit.state

import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.util.fastForEach
import com.gitee.wsl.compose.ext.text.DefaultParagraphStyle
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.ext.getCommonStyle
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.ext.getCommonType
import com.gitee.wsl.compose.ext.text.isSpecifiedFieldsEquals
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.DefaultParagraphType
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.list.OrderedList
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.list.UnorderedList
import com.gitee.wsl.compose.ext.text.unmerge


/**
 * Toggle the [ParagraphStyle]
 * If the passed paragraph style doesn't exist in the [currentParagraphStyle] it's going to be added.
 * If the passed paragraph style already exists in the [currentParagraphStyle] it's going to be removed.
 *
 * Example: You can toggle TextAlign Center by passing:
 *
 * ```
 * ParagraphStyle(textAlign = TextAlign.Center)
 * ```
 *
 * @param paragraphStyle the paragraph style that is going to be toggled.
 * Only the specified params are going to be toggled, and the non specified ones are going to be ignored.
 * @see [addParagraphStyle]
 * @see [removeParagraphStyle]
 */
fun RichTextState.toggleParagraphStyle(paragraphStyle: ParagraphStyle) {
    if (currentParagraphStyle.isSpecifiedFieldsEquals(paragraphStyle))
        removeParagraphStyle(paragraphStyle)
    else
        addParagraphStyle(paragraphStyle)
}

/**
 * Add new [ParagraphStyle] to the [currentParagraphStyle]
 *
 * Example: You can add TextAlign Center by passing:
 *
 * ```
 * ParagraphStyle(textAlign = TextAlign.Center)
 * ```
 *
 * @param paragraphStyle the paragraph style that is going to be added to the [currentParagraphStyle].
 * Only the specified params are going to be applied, and the non specified ones are going to be ignored.
 * @see [removeParagraphStyle]
 * @see [toggleParagraphStyle]
 */
fun RichTextState.addParagraphStyle(paragraphStyle: ParagraphStyle) {
    if (!currentParagraphStyle.isSpecifiedFieldsEquals(paragraphStyle)) {
        // If the selection is collapsed, we add the paragraph style to the paragraph containing the selection
        if (selection.collapsed) {
            val paragraph = getRichParagraphByTextIndex(selection.min - 1) ?: return
            paragraph.paragraphStyle = paragraph.paragraphStyle.merge(paragraphStyle)
        }
        // If the selection is not collapsed, we add the paragraph style to all the paragraphs in the selection
        else {
            val paragraphs = getRichParagraphListByTextRange(selection)
            if (paragraphs.isEmpty()) return
            paragraphs.fastForEach { it.paragraphStyle = it.paragraphStyle.merge(paragraphStyle) }
        }
        // We update the annotated string to reflect the changes
        updateAnnotatedString()
        // We update the current paragraph style to reflect the changes
        updateCurrentParagraphStyle()
    }
}

/**
 * Remove an existing [ParagraphStyle] from the [currentParagraphStyle]
 *
 * Example: You can remove TextAlign Center by passing:
 *
 * ```
 * ParagraphStyle(textAlign = TextAlign.Center)
 * ```
 *
 * @param paragraphStyle the paragraph style that is going to be removed from the [currentParagraphStyle].
 * Only the specified params are going to be removed, and the non specified ones are going to be ignored.
 * @see [addParagraphStyle]
 * @see [toggleParagraphStyle]
 */
fun RichTextState.removeParagraphStyle(paragraphStyle: ParagraphStyle) {
    if (currentParagraphStyle.isSpecifiedFieldsEquals(paragraphStyle)) {
        // If the selection is collapsed, we remove the paragraph style from the paragraph containing the selection
        if (selection.collapsed) {
            val paragraph = getRichParagraphByTextIndex(selection.min - 1) ?: return
            paragraph.paragraphStyle = paragraph.paragraphStyle.unmerge(paragraphStyle)
        }
        // If the selection is not collapsed, we remove the paragraph style from all the paragraphs in the selection
        else {
            val paragraphs = getRichParagraphListByTextRange(selection)
            if (paragraphs.isEmpty()) return
            paragraphs.fastForEach { it.paragraphStyle = it.paragraphStyle.unmerge(paragraphStyle) }
        }
        // We update the annotated string to reflect the changes
        updateAnnotatedString()
        // We update the current paragraph style to reflect the changes
        updateCurrentParagraphStyle()
    }
}


/**
 * Updates the [currentAppliedParagraphStyle] to the [ParagraphStyle] that should be applied to the current selection.
 */
internal fun RichTextState.updateCurrentParagraphStyle() {
    if (selection.collapsed) {
        val richParagraph = getRichParagraphByTextIndex(selection.min - 1)

        currentRichParagraphType = richParagraph?.type
            ?: richParagraphList.firstOrNull()?.type ?: DefaultParagraphType()
        currentAppliedParagraphStyle = richParagraph?.paragraphStyle
            ?: richParagraphList.firstOrNull()?.paragraphStyle ?: DefaultParagraphStyle
        isUnorderedList = richParagraph?.type is UnorderedList
        isOrderedList = richParagraph?.type is OrderedList
        isList = isUnorderedList || isOrderedList
        canIncreaseListLevel = richParagraph?.let { canIncreaseListLevel(listOf(it)) } == true
        canDecreaseListLevel = richParagraph?.let { canDecreaseListLevel(listOf(it)) } == true
    } else {
        val richParagraphList = getRichParagraphListByTextRange(selection)

        currentRichParagraphType = richParagraphList
            .getCommonType()
            ?: DefaultParagraphType()
        currentAppliedParagraphStyle = richParagraphList
            .getCommonStyle()
            ?: ParagraphStyle()

        isUnorderedList = richParagraphList.all { it.type is UnorderedList }
        isOrderedList = richParagraphList.all { it.type is OrderedList }
        isList = richParagraphList.all { it.type is UnorderedList || it.type is OrderedList }
        canIncreaseListLevel = canIncreaseListLevel(richParagraphList)
        canDecreaseListLevel = canDecreaseListLevel(richParagraphList)
    }
}